package org.myspringframework;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ClassPathXmlApplicationContext implements ApplicationContext {
    private Map<String, Object> singletonObjects = new HashMap<>();
    private String configLocation;


    public ClassPathXmlApplicationContext(String configLocation) {
        this.configLocation = configLocation;
        try {
            //读xml的配置文件
            SAXReader saxReader = new SAXReader();
            InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(configLocation);
            Document document = saxReader.read(in);
            List<Node> beanList = document.selectNodes("//bean");
            beanList.forEach(node -> {
                System.out.println(node);
                Element beanEle = (Element) node;
                //获取xml中bean的属性
                String beanId = beanEle.attributeValue("id");
                String beanClassPath = beanEle.attributeValue("class");
                try {
                    //通过反射获取对象
                    Class<?> clazz = Class.forName(beanClassPath);
                    Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();
                    Object beanObject = declaredConstructor.newInstance();
                    //放进map集合
                    singletonObjects.put(beanId, beanObject);
                    System.out.println(singletonObjects);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            beanList.forEach(node -> {
                try {
                    Element beanEle = (Element) node;
                    String beanId = beanEle.attributeValue("id");
                    String beanClassPath = beanEle.attributeValue("class");
                    Class<?> aClass = Class.forName(beanClassPath);
                    List<Element> properties = beanEle.elements("property");
                    properties.forEach(property -> {
                        try {
                            //获取属性名
                            String propertyName = property.attributeValue("name");
                            //获取属性值，简单数据类型
                            String value = property.attributeValue("value");
                            //获取值，复杂数据类型
                            String ref = property.attributeValue("ref");
                            //拼接set方法名。如：属性名是name，则方法名：setName
                            String setMethName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);
                            System.out.println("前：" + propertyName + "," + value + "," + ref + "," + setMethName);
                            //获取属性类型
                            Field field = aClass.getDeclaredField(propertyName);
                            Class<?> fieldType = field.getType();
                            //执行set方法
                            Method setMethodObject = aClass.getMethod(setMethName, fieldType);
                            System.out.println("后：" + field + "," + setMethodObject + "," + singletonObjects.get(beanId));
                            if (value != null) {
                                System.out.println("执行set方法:" + setMethodObject + "," + singletonObjects.get(beanId) + "," + value);
                                //获取简单类型，进行数据强制转换，从而传参(xml里面获取到的数据是String类型的)
                                String fieldTypeSimpleName = fieldType.getSimpleName();//"String"
                                switch (fieldTypeSimpleName) {
                                    case "String":
                                        setMethodObject.invoke(singletonObjects.get(beanId), value);
                                        break;
                                    case "int":
                                        setMethodObject.invoke(singletonObjects.get(beanId), Integer.valueOf(value));
                                        break;
                                    default:
                                        System.out.println("暂不支持该类型");
                                }

                            }
                            if (ref != null) {
                                setMethodObject.invoke(singletonObjects.get(beanId), singletonObjects.get(ref));
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    });

                } catch (Exception e) {
                    e.printStackTrace();
                }

            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public Object getBean(String beanName) {
        return singletonObjects.get(beanName);
    }
}
